﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Web;

namespace d1Project.Tools
{
    //图像处理工具
    public static class ImageHelper
    {
        /// <summary>
        /// 验证码图片
        /// </summary>
        /// <param name="validateCode"></param>
        /// <returns></returns>
        public static Image CreateValidateGraphic(string validateCode)
        {
            Bitmap image = new Bitmap((int)Math.Ceiling(validateCode.Length * 12.0), 22);
            Graphics g = Graphics.FromImage(image);
            //生成随机生成器
            Random random = new Random();
            //清空图片背景色
            g.Clear(Color.White);
            //画图片的干扰线
            for (int i = 0; i < 25; i++)
            {
                int x1 = random.Next(image.Width);
                int x2 = random.Next(image.Width);
                int y1 = random.Next(image.Height);
                int y2 = random.Next(image.Height);
                g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2);
            }
            Font font = new Font("Arial", 12, (FontStyle.Bold | FontStyle.Italic));
            LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height),
             Color.Blue, Color.DarkRed, 1.2f, true);
            g.DrawString(validateCode, font, brush, 3, 2);
            //画图片的前景干扰点
            for (int i = 0; i < 100; i++)
            {
                int x = random.Next(image.Width);
                int y = random.Next(image.Height);
                image.SetPixel(x, y, Color.FromArgb(random.Next()));
            }
            //画图片的边框线
            g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1);
            return image;
        }

        /// <summary>
        /// 缩略图--按比例压缩图片
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="maxLength">最大边长</param>
        /// <param name="maxByteSize">图片大小 1 0000=10kb</param>
        /// <returns></returns>
        public static Image ThumbImage(Image image, int maxLength, long maxByteSize)
        {
            try
            {
                int oriWidth = image.Width;
                int oriHeigh = image.Height;
                float oriRatio = (float)oriHeigh / (float)oriWidth;//高宽比

                int targetWidth;
                int targetHeigh;

                if (oriWidth >= oriHeigh && oriWidth > maxLength)
                {
                    targetWidth = maxLength;
                    targetHeigh = (int)((float)maxLength * (float)oriRatio);
                }
                else if (oriWidth <= oriHeigh && oriHeigh > maxLength)
                {
                    targetWidth = (int)((float)maxLength / (float)oriRatio);
                    targetHeigh = maxLength;
                }
                else
                {
                    targetWidth = oriWidth;
                    targetHeigh = oriHeigh;
                }
                Bitmap bmp = (Bitmap)image;
                Size s = new Size(targetWidth, targetHeigh);
                var newBmp = new Bitmap(bmp, s);
                //100 000=100kb 1 0000=10kb 
                var ms = TrySaveJpeg(newBmp, maxByteSize);

                newBmp.Dispose();
                bmp.Dispose();
                Image targetImage = Image.FromStream(ms);
                return targetImage;
            }
            catch (Exception )
            {
                return null;
            }
        }

       /// <summary>
        /// 缩略图--切图
       /// </summary>
       /// <param name="stream"></param>
        /// <param name="t_width">缩略图宽</param>
        /// <param name="t_height">缩略图高</param>
        /// <param name="maxByteSize">图片大小 1 0000=10kb</param>
       /// <returns></returns>
        public static Image CutImage(Image image,int t_width, int t_height, long maxByteSize)
        {
            System.Drawing.Bitmap bmp = null;
            System.Drawing.Graphics graphic = null;
            try
            {

                int ori_paste_x = 0;
                int ori_paste_y = 0;
                int ori_width = image.Width;//截取原图宽度
                int ori_height = image.Height;//截取原图高度
                int target_paste_x = 0;
                int target_paste_y = 0;


                float target_ratio = (float)t_width / (float)t_height;//缩略图 宽、高的比例
                float ori_ratio = (float)ori_width / (float)ori_height;//原图 宽、高的比例

                if (target_ratio > ori_ratio)//宽拉长
                {
                    ori_height = (int)Math.Floor((float)ori_width / target_ratio);
                }
                else
                {
                    ori_width = (int)Math.Floor((float)ori_height * target_ratio);
                }
                ori_paste_x = (image.Width - ori_width) / 2;
                ori_paste_y = (image.Height - ori_height) / 2;

                //---------------------------------------------------------------------------------------
                bmp = new Bitmap(t_width, t_height);
                graphic = System.Drawing.Graphics.FromImage(bmp);
                // graphic.FillRectangle(new System.Drawing.SolidBrush(System.Drawing.Color.White), new System.Drawing.Rectangle(0, 0, t_width, t_height));//背景颜色
                graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                graphic.Clear(Color.White);//背景
                Rectangle SrcRec = new Rectangle(ori_paste_x, ori_paste_y, ori_width, ori_height);
                Rectangle targetRec = new Rectangle(target_paste_x, target_paste_y, t_width, t_height);
                graphic.DrawImage(image, targetRec, SrcRec, GraphicsUnit.Pixel);

                var ms = TrySaveJpeg(bmp, maxByteSize);
                bmp.Dispose();

                Image targetImage = Image.FromStream(ms);
                return targetImage;
            }
            catch
            {
                HttpContext.Current.Response.StatusCode = 500;
                HttpContext.Current.Response.Write("An error occured");
                HttpContext.Current.Response.End();
            }
            finally
            {
                // Clean up
                if (bmp != null) bmp.Dispose();
                if (graphic != null) graphic.Dispose();
                if (image != null) image.Dispose();
            }
            return null;
        }

        /// <summary>
        /// 内部调用--控制图片质量
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="maxByteSize"></param>
        /// <returns></returns>
        private static Stream TrySaveJpeg(Bitmap bitmap, long maxByteSize)
        {
            MemoryStream msOld = new MemoryStream(),
                msNew = new MemoryStream();

            var codec = ImageCodecInfo.GetImageEncoders().FirstOrDefault(c => c.MimeType == "image/jpeg");
            var encParam = new EncoderParameters(1);

            encParam.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 0L);
            bitmap.Save(msOld, codec, encParam);
            if (msOld.Length > maxByteSize)
            {
                return msOld; //最差画质
            }
            encParam.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
            bitmap.Save(msNew, codec, encParam);

            if (msNew.Length < maxByteSize)
            {
                msNew.Seek(0, SeekOrigin.Begin);
                return msNew; //最佳画质
            }
            //假设文件大小和图像质量成正相关 这里没有具体测试 姑且认为成立
            //用二分法找到最合适的图像质量 
            long start = 1, end = 99;
            while (start < end)
            {
                long qua = (start + end) / 2;
                encParam.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qua);
                msNew.SetLength(0);
                bitmap.Save(msNew, codec, encParam);
                if (msNew.Length == maxByteSize)
                {
                    msNew.Seek(0, SeekOrigin.Begin);
                    return msNew;
                }
                else if (msNew.Length > maxByteSize)
                {
                    end = qua - 1;
                }
                else if (msNew.Length < maxByteSize)
                {
                    start = qua + 1;
                    MemoryStream temp = msNew;
                    msNew = msOld;
                    msOld = temp; //保存一个小于指定大小 并且最接近的
                }
            }
            msOld.Seek(0, SeekOrigin.Begin);
            return msOld;
        }
    }
}